<?php

/**
 * This file is part of the Codizer package.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @copyright   Copyright (c) 2010 Advisa (http://www.advisa.fr)
 * @author      Codizer Core Team <team@codizer.org>
 * @package     Codizer
 */

class f_builder_FormBuilder
{
	/**
	 * @var f_xml_Xpath
	 */
	private $xmlObject;
	private $moduleName;
	private $formName;
	private $templateFilename;
	private $path;	
	private $templateFolder;	
	private $specialFields;	
	private $inWebapp = false;
	
	/**
	 * @param f_xml_Xpath $xmlObject
	 * @return f_builder_DocumentBuilder
	 */
	private function __construct(f_xml_Xpath $xmlObject)
	{		
		if(is_object($xmlObject) && ($xmlObject instanceof f_xml_Xpath))
		{
			$this->xmlObject = $xmlObject;
		}
		else
		{
			throw new Exception("XML is not valid");
		}
		return $this;
	}
	
	/**
	 * Sets initial document variables
	 *
	 */
	private function setVariables()
	{		
		try
		{
			$prefix = "m_";
			$dir = MODULES_DIR;
			
			if($this->inWebapp == true)
			{
				$prefix = "w_";
				$dir = WEBAPP_MODULES_DIR;
			}
			
			// Path
			$this->path = $dir;
			
			// Builder template folder
			$this->templateFolder = FRAMEWORK_HOME.DS."form".DS."templates".DS;
									
			// Module name
			$this->moduleName = $this->getModuleName($this->xmlObject);
			 
			// Generated form files name
			$this->formName = $this->getDocumentName($this->xmlObject);
			$this->templateFilename = $dir.DS.$this->moduleName.DS."templates".DS."block".DS."Form".ucfirst($this->formName).".html";
			
			// Additional properties			
			$this->properties = $this->xmlObject->fromXpath("fields/formcomponent")->getElements();
		}
		catch(Exception $e)
		{
			throw new Exception($e);
		}
	}
	
	/**
	 * Retrieve document name from the xml file 
	 * 
	 * @return string
	 */	
	private function getDocumentName($xmlObject)
	{
		$attributes = $xmlObject->fromXpath("document")->getAttributes();
		
		if(!isset($attributes["name"]) || is_null($attributes["name"]) || $attributes["name"] == "")
		{
			$tmp = explode(DS,$xmlObject->getXmlFilePath());
			return str_replace(".xml","",end($tmp));
		}		
		
		return $attributes["name"];
	}

	
	/**
	 * Retrieve module name from the xml file 
	 * 
	 * @return string
	 */
	private function getModuleName($xmlObject)
	{
		$attributes = $xmlObject->fromXpath("document")->getAttributes();
		
		if(!isset($attributes["module"]) || is_null($attributes["module"]) || $attributes["module"] == "")
		{
			$fileDetails = f_file_File::getInstance($xmlObject->getXmlFilePath());
					
			$filename = $fileDetails->getFileName();
			$dirname = $fileDetails->getDir();
			
			if(strstr($dirname, MODULES_DIR))
			{
				$dirname = str_replace(MODULES_DIR.DS, "", $dirname);
			}
			else
			{
				$dirname = str_replace(WEBAPP_MODULES_DIR.DS, "", $dirname);
			}
			
			$vars = explode(DS, $dirname);
			
			return $vars[0];				
		}

		return $attributes["module"];
	}
		
	/**
	 * Get instance
	 *
	 * @param f_xml_Xpath $xmlObject
	 * @return f_builder_DocumentBuilder
	 */
	public static function getInstance(f_xml_Xpath $xmlObject)
	{
		return new self($xmlObject);	
	}
	
	/**
	 * Main building method
	 */
	public function build()
	{
		$this->setVariables();
		$this->buildForm();	
	}
	
	/**
	 * Building Form classes and templates
	 */
	public function buildForm()
	{	
		if(!is_null($this->properties))
		{		
			$listFields = "";
			$hiddenFields = "";
			$withUpload = "";
						
			/* @var $var f_xml_XmlElement */
			foreach($this->properties as $var)
			{
				$params = array();
				$hidden = false;
				
				// Attributes of current field
				$attributes = $var->disableI18n()->getAttributes();
				
				// Label
				if(isset($attributes['label']) == false)
				{
					$attributes['label'] = $attributes['name'];
				}

				// Check if label is a key.local
				if(strpos($attributes['label'], "key.local") !== false)
				{
					$attributes['label'] = f_locale_Manager::getLocale($attributes['label']);
				}		

				$hasCheckers = false;
				if(count($var->getSubElements("check")) > 0)
				{
					$hasCheckers = true;
				}
				
				// Type
				switch(strtolower($attributes['type']))
				{
					case "radio":
					case "select":					
						$attributes['subElements'] = $var->getSubElements('subelement');					
						$listFields .= $this->buildField($attributes, $hasCheckers);
						break;
								
					case "hidden":
						$hiddenFields .= $this->buildField($attributes, $hasCheckers);
						break;
					
					case "file":
						$withUpload = 'enctype="multipart/form-data" ';
						if(isset($attributes['accept']))
						{
							$withUpload .= 'accept="'.$attributes['accept'].'"';
						}
						$listFields .= $this->buildField($attributes, $hasCheckers);
						break;
						
					default:
						$listFields .= $this->buildField($attributes, $hasCheckers);
						break;
				}
										
			}					

			// Generate Action class
			$actions = f_builder_ActionBuilder::getInstance()
					->setModuleName($this->moduleName)
					->setActionName("block_Form".ucfirst($this->formName))
			        ->setTemplateName("Form".ucfirst($this->formName).".html")
					->setSpecialFields($this->specialFields)
					->buildForm($this->formName, $this->path);

			
			$template = f_template_Template::getInstance()->disableCache();
			
			// Generate Form html 
			$templateFile = $this->templateFolder."form_Base.tpl";
			$template->setTemplate($templateFile);
			$template->assign("divName", $this->formName);
			$template->assign("formName", "Form".ucfirst($this->formName));
			$template->assign("fields", $listFields);
			$template->assign("hiddenFields", $hiddenFields);
			$template->assign("withUpload", $withUpload);
			
			$this->writeFile($this->templateFilename, $template->render(), true);
		}
		else
		{
			echo COLOR_RED."No properties. Only generating base properties.\n";
		}		
	}	
	
	private function buildField($attributes, $hasCheckers)
	{
		$templateFile = $this->templateFolder."field_".ucfirst($attributes['type']).".tpl";
		$otherAttributes = $this->getOtherAttributes($attributes);
		
		$template = f_template_Template::getInstance();
		$template->setTemplate($templateFile)->disableCache();
		$template->assign("name", $attributes['name']);
		$template->assign("label", $attributes['label']);
		$template->assign("hasCheckers", $hasCheckers);
		$template->assign("formName", "Form".ucfirst($this->formName));
		$template->assign("otherAttributes", $otherAttributes);
		
		// If "from" isset, mean that we have to populate the current field with an action or a document
		if(isset($attributes['from']) == true)
		{
			$this->specialFields[] = $attributes;
			$template->assign("specialField", true);	
		}
		elseif(isset($attributes['subElements']) == true)
		{
			// Else we check for subelements
			$template->assign("subElements", $this->getFormatedSubElement($attributes['subElements']));	
		}
	
		if(isset($attributes['value']))
		{
			$template->assign("value", $attributes['value']);
		}

		// In case of a multiple select field
		if($otherAttributes != "" && $attributes['type'] == "select" && preg_match("/multiple=('|\")multiple('|\")/", $otherAttributes) != 0)
		{
			$template->assign("multiple", true);	
		}		
		
		return $template->render();			
	}
		
	private function getFormatedSubElement($params)
	{
		if($params != null && count($params) >0)
		{
			$result = array();
			
			// Foreach SubElement
			foreach($params as $param)
			{
				// Get his attribues
				$tmpAttributes = $param->getAttributes();
			
				// Check for label
				if(isset($tmpAttributes['label']) == false)
				{
					$tmpAttributes['label'] = $tmpAttributes['name'];
				}
				
				// Check if label is a key.local
				if(strpos($tmpAttributes['label'],"key.local") !== false)
				{
					$tmpAttributes['label'] = f_locale_Manager::getLocale($tmpAttributes['label']);
				}			
				
				// Retrieve other field attributes
				$tmpAttributes['subOtherAttributes'] = $this->getOtherAttributes($tmpAttributes);
				
				$result[] = $tmpAttributes;
			}
			return $result;
		}
		return null;
	}
	
	private function getOtherAttributes($attributes)
	{
		$result = "";
		
		$exclude = array("type", "label", "name", "value", "action", "from", "subElements", "foreignField", "accept");
		
		foreach($attributes as $key => $value)
		{
			if(!in_array($key, $exclude))
			{
				$result .= $key. "=\"" . $value. "\" ";
			}
		}

		return $result;
	}
	
	/**
	 * Set if document is generated in webapp
	 *
	 * @param boolean $boolean
	 * @return f_builder_Documentbuilder
	 */
	public function isInWebapp($boolean)
	{
		$this->inWebapp = $boolean;
		return $this;
	}
	
	/**
	 * Write file
	 *
	 * @param string $fileName
	 * @param string $fileContent
	 */
	private function writeFile($fileName, $fileContent, $forceRewrite = false)
	{
		if($forceRewrite == false)
		{
			if(file_exists($fileName))
			{
				echo COLOR_RED."Skipped".COLOR_NORMAL." -> File ".$fileName." already exist, remove if necessary\n";
				return null;
			}
		}

		echo COLOR_GREEN."Writing".COLOR_NORMAL." -> ".$fileName."\n";
		
		$tmpPath = substr($fileName,0,strrpos($fileName,DS));
		
		if(is_dir($tmpPath) == false)
		{
			mkdir($tmpPath, 0775, true);
		}		
		$fp = fopen($fileName, "w");
		fwrite($fp, $fileContent);
		fclose($fp);				
	}
}